]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOS9/Mac OS Test Searcher.c
mDNSResponder-98.tar.gz
[apple/mdnsresponder.git] / mDNSMacOS9 / Mac OS Test Searcher.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: Mac\040OS\040Test\040Searcher.c,v $
26 Revision 1.21 2004/12/16 20:49:34 cheshire
27 <rdar://problem/3324626> Cache memory management improvements
28
29 Revision 1.20 2004/10/19 21:33:18 cheshire
30 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
31 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
32 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
33
34 Revision 1.19 2004/09/17 01:08:50 cheshire
35 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
36 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
37 declared in that file are ONLY appropriate to single-address-space embedded applications.
38 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
39
40 Revision 1.18 2004/09/16 21:59:16 cheshire
41 For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
42
43 Revision 1.17 2004/06/10 04:37:27 cheshire
44 Add new parameter in mDNS_GetDomains()
45
46 Revision 1.16 2004/03/12 21:30:25 cheshire
47 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
48 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
49
50 Revision 1.15 2004/01/24 23:55:15 cheshire
51 Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
52
53 Revision 1.14 2003/11/14 21:27:09 cheshire
54 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
55 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
56
57 Revision 1.13 2003/08/14 02:19:54 cheshire
58 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
59
60 Revision 1.12 2003/08/12 19:56:24 cheshire
61 Update to APSL 2.0
62
63 */
64
65 #include <stdio.h> // For printf()
66 #include <Events.h> // For WaitNextEvent()
67 #include <SIOUX.h> // For SIOUXHandleOneEvent()
68
69 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
70 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
71
72 typedef struct
73 {
74 OTLIFO serviceinfolist;
75 Boolean headerPrinted;
76 Boolean lostRecords;
77 } SearcherServices;
78
79 typedef struct { ServiceInfo i; mDNSBool add; mDNSBool dom; OTLink link; } linkedServiceInfo;
80
81 // These don't have to be globals, but their memory does need to remain valid for as
82 // long as the search is going on. They are declared as globals here for simplicity.
83 #define RR_CACHE_SIZE 1000
84 static CacheEntity rrcachestorage[RR_CACHE_SIZE];
85 static mDNS mDNSStorage;
86 static mDNS_PlatformSupport PlatformSupportStorage;
87 static SearcherServices services;
88 static DNSQuestion browsequestion, domainquestion;
89
90 // PrintServiceInfo prints the service information to standard out
91 // A real application might want to do something else with the information
92 static void PrintServiceInfo(SearcherServices *services)
93 {
94 OTLink *link = OTReverseList(OTLIFOStealList(&services->serviceinfolist));
95
96 while (link)
97 {
98 linkedServiceInfo *ls = OTGetLinkObject(link, linkedServiceInfo, link);
99 ServiceInfo *s = &ls->i;
100
101 if (!services->headerPrinted)
102 {
103 printf("%-55s Type Domain IP Address Port Info\n", "Name");
104 services->headerPrinted = true;
105 }
106
107 if (ls->dom)
108 {
109 char c_dom[MAX_ESCAPED_DOMAIN_NAME];
110 ConvertDomainNameToCString(&s->name, c_dom);
111 if (ls->add) printf("%-55s available for browsing\n", c_dom);
112 else printf("%-55s no longer available for browsing\n", c_dom);
113 }
114 else
115 {
116 domainlabel name;
117 domainname type, domain;
118 char c_name[MAX_DOMAIN_LABEL+1], c_type[MAX_ESCAPED_DOMAIN_NAME], c_dom[MAX_ESCAPED_DOMAIN_NAME], c_ip[20];
119 DeconstructServiceName(&s->name, &name, &type, &domain);
120 ConvertDomainLabelToCString_unescaped(&name, c_name);
121 ConvertDomainNameToCString(&type, c_type);
122 ConvertDomainNameToCString(&domain, c_dom);
123 sprintf(c_ip, "%d.%d.%d.%d", s->ip.ip.v4.b[0], s->ip.ip.v4.b[1], s->ip.ip.v4.b[2], s->ip.ip.v4.b[3]);
124
125 printf("%-55s %-16s %-14s ", c_name, c_type, c_dom);
126 if (ls->add) printf("%-15s %5d %#s\n", c_ip, mDNSVal16(s->port), s->TXTinfo);
127 else printf("Removed\n");
128 }
129
130 link = link->fNext;
131 OTFreeMem(ls);
132 }
133 }
134
135 // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo()
136 // enqueues a record for PrintServiceInfo() to print.
137 // Note, a browsing application would *not* normally need to get all this information --
138 // all it needs is the name, to display to the user.
139 // Finding out the address, port, and txtinfo should be deferred to the time that the user
140 // actually needs to contact the service to use it.
141 static void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
142 {
143 SearcherServices *services = (SearcherServices *)query->ServiceInfoQueryContext;
144 linkedServiceInfo *info = (linkedServiceInfo *)(query->info);
145 if (query->info->ip.type == mDNSAddrType_IPv4)
146 {
147 mDNS_StopResolveService(m, query); // For this test code, one answer is sufficient
148 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
149 OTFreeMem(query);
150 }
151 }
152
153 // When a new named instance of a service is found, FoundInstance() is called.
154 // In this sample code we turn around and immediately issue a query to resolve that service name to
155 // find its address, port, and txtinfo, but a normal browing application would just display the name.
156 static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
157 {
158 #pragma unused (question)
159 SearcherServices *services = (SearcherServices *)question->QuestionContext;
160 linkedServiceInfo *info;
161
162 debugf("FoundInstance %##s PTR %##s", answer->name->c, answer->rdata->u.name.c);
163
164 if (answer->rrtype != kDNSType_PTR) return;
165 if (!services) { debugf("FoundInstance: services is NULL"); return; }
166
167 info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo));
168 if (!info) { services->lostRecords = true; return; }
169
170 info->i.name = answer->rdata->u.name;
171 info->i.InterfaceID = answer->InterfaceID;
172 info->i.ip.type = mDNSAddrType_IPv4;
173 info->i.ip.ip.v4 = zerov4Addr;
174 info->i.port = zeroIPPort;
175 info->add = AddRecord;
176 info->dom = mDNSfalse;
177
178 if (!AddRecord) // If TTL == 0 we're deleting a service,
179 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
180 else // else we're adding a new service
181 {
182 ServiceInfoQuery *q = (ServiceInfoQuery *)OTAllocMem(sizeof(ServiceInfoQuery));
183 if (!q) { OTFreeMem(info); services->lostRecords = true; return; }
184 mDNS_StartResolveService(m, q, &info->i, FoundInstanceInfo, services);
185 }
186 }
187
188 static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
189 {
190 #pragma unused (m)
191 #pragma unused (question)
192 SearcherServices *services = (SearcherServices *)question->QuestionContext;
193 linkedServiceInfo *info;
194
195 debugf("FoundDomain %##s PTR %##s", answer->name->c, answer->rdata->u.name.c);
196
197 if (answer->rrtype != kDNSType_PTR) return;
198 if (!services) { debugf("FoundDomain: services is NULL"); return; }
199
200 info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo));
201 if (!info) { services->lostRecords = true; return; }
202
203 info->i.name = answer->rdata->u.name;
204 info->i.InterfaceID = answer->InterfaceID;
205 info->i.ip.type = mDNSAddrType_IPv4;
206 info->i.ip.ip.v4 = zerov4Addr;
207 info->i.port = zeroIPPort;
208 info->add = AddRecord;
209 info->dom = mDNStrue;
210
211 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
212 }
213
214 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
215 static Boolean YieldSomeTime(UInt32 milliseconds)
216 {
217 extern Boolean SIOUXQuitting;
218 EventRecord e;
219 WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL);
220 SIOUXHandleOneEvent(&e);
221 return(SIOUXQuitting);
222 }
223
224 int main()
225 {
226 mStatus err;
227 Boolean DoneSetup = false;
228 void *tempmem;
229
230 SIOUXSettings.asktosaveonclose = false;
231 SIOUXSettings.userwindowtitle = "\pMulticast DNS Searcher";
232 SIOUXSettings.rows = 40;
233 SIOUXSettings.columns = 132;
234
235 printf("Multicast DNS Searcher\n\n");
236 printf("This software reports errors using MacsBug breaks,\n");
237 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
238 printf("******************************************************************************\n");
239
240 err = InitOpenTransport();
241 if (err) { debugf("InitOpenTransport failed %d", err); return(err); }
242
243 err = mDNS_Init(&mDNSStorage, &PlatformSupportStorage, rrcachestorage, RR_CACHE_SIZE,
244 mDNS_Init_DontAdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
245 if (err) return(err);
246
247 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
248 tempmem = OTAllocMem(0x10000);
249 if (tempmem) OTFreeMem(tempmem);
250 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
251
252 services.serviceinfolist.fHead = NULL;
253 services.headerPrinted = false;
254 services.lostRecords = false;
255
256 while (!YieldSomeTime(35))
257 {
258 #if MDNS_ONLYSYSTEMTASK
259 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
260 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
261 extern void mDNSPlatformIdle(mDNS *const m);
262 mDNSPlatformIdle(&mDNSStorage); // Only needed for debugging version
263 #endif
264 if (mDNSStorage.mDNSPlatformStatus == mStatus_NoError && !DoneSetup)
265 {
266 domainname srvtype, srvdom;
267 DoneSetup = true;
268 printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
269 MakeDomainNameFromDNSNameString(&srvtype, "_http._tcp.");
270 MakeDomainNameFromDNSNameString(&srvdom, "local.");
271 err = mDNS_StartBrowse(&mDNSStorage, &browsequestion, &srvtype, &srvdom, mDNSInterface_Any, mDNSfalse, FoundInstance, &services);
272 if (err) break;
273 err = mDNS_GetDomains(&mDNSStorage, &domainquestion, mDNS_DomainTypeBrowse, NULL, mDNSInterface_Any, FoundDomain, &services);
274 if (err) break;
275 }
276
277 if (services.serviceinfolist.fHead)
278 PrintServiceInfo(&services);
279
280 if (services.lostRecords)
281 {
282 services.lostRecords = false;
283 printf("**** Warning: Out of memory: Records have been missed.\n");
284 }
285 }
286
287 mDNS_StopBrowse(&mDNSStorage, &browsequestion);
288 mDNS_Close(&mDNSStorage);
289 return(0);
290 }